home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 126-150 / disk_147 / src / extend.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  20KB  |  798 lines

  1. /*
  2.  *    Extended (M-X) commands, rebinding, and 
  3.  *    startup file processing.
  4.  */
  5. #include    "def.h"
  6. #include    "kbd.h"
  7.  
  8. #ifndef NO_MACRO
  9. #include    "macro.h"
  10. #endif
  11.  
  12. #ifdef    FKEYS
  13. #include    "key.h"
  14. #ifndef    NO_STARTUP
  15. #ifndef    BINDKEY
  16. #define    BINDKEY        /* bindkey is used by FKEYS startup code */
  17. #endif
  18. #endif
  19. #endif
  20.  
  21. extern    char    *strncpy();
  22. extern    int rescan();
  23.  
  24. /* insert a string, mainly for use from macros (created by selfinsert) */
  25. /*ARGSUSED*/
  26. insert(f, n)
  27. int f, n;
  28. {
  29.     register char *cp;
  30.     char buf[128];
  31. #ifndef NO_MACRO
  32.     register int count;
  33.     int c;
  34.  
  35.     if(inmacro) {
  36.     while(--n >= 0) {
  37.         for(count = 0; count < maclcur->l_used; count++) {
  38.         if((((c=maclcur->l_text[count]) == '\n') ? lnewline()
  39.             : linsert(1, c)) != TRUE) return FALSE;
  40.         }
  41.     }
  42.     maclcur = maclcur->l_fp;
  43.     return TRUE;
  44.     }
  45.     if(n==1) thisflag |= CFINS; /* CFINS means selfinsert can tack on end */
  46. #endif
  47.     if(eread("Insert: ", buf, sizeof(buf), EFNEW) == FALSE) return FALSE;
  48.     while(--n >= 0) {
  49.     cp = buf;
  50.     while(*cp) {
  51.         if(((*cp == '\n') ? lnewline() : linsert(1, *cp)) != TRUE)
  52.         return FALSE;
  53.         cp++;
  54.     }
  55.     }
  56.     return TRUE;
  57. }
  58.  
  59. /*
  60.  * Bind a key to a function.  Cases range from the trivial (replacing an
  61.  * existing binding) to the extremly complex (creating a new prefix in a
  62.  * map_element that already has one, so the map_element must be split,
  63.  * but the keymap doesn't have enough room for another map_element, so
  64.  * the keymap is reallocated).    No attempt is made to reclaim space no
  65.  * longer used, if this is a problem flags must be added to indicate
  66.  * malloced verses static storage in both keymaps and map_elements.
  67.  * Structure assignments would come in real handy, but K&R based compilers
  68.  * don't have them.  Care is taken so running out of memory will leave
  69.  * the keymap in a usable state.
  70.  */
  71. static int remap(curmap, c, funct, pref_map)
  72. register KEYMAP    *curmap;/* pointer to the map being changed */
  73. int    c;        /* character being changed */
  74. PF    funct;        /* function being changed to */
  75. KEYMAP    *pref_map;    /* if funct==prefix, map to bind to or NULL for new */
  76. /* extern MAP_ELEMENT *ele;    must be set before calling */
  77. {
  78.     register int i;
  79.     int    n1, n2, nold;
  80.     KEYMAP    *mp;
  81.     PF    *pfp;
  82.     MAP_ELEMENT *mep;
  83.     static    KEYMAP *realocmap();
  84.  
  85.     if(ele >= &curmap->map_element[curmap->map_num] || c < ele->k_base) {
  86.         if(ele > &curmap->map_element[0] && (funct!=prefix ||
  87.             (ele-1)->k_prefmap==NULL)) {
  88.         n1 = c - (ele-1)->k_num;
  89.         } else n1 = HUGE;
  90.         if(ele < &curmap->map_element[curmap->map_num] && (funct!=prefix ||
  91.             ele->k_prefmap==NULL)) {
  92.         n2 = ele->k_base - c;
  93.         } else n2 = HUGE;
  94.         if(n1 <= MAPELEDEF && n1 <= n2) {
  95.         ele--;
  96.         if((pfp = (PF *)malloc((unsigned)(c - ele->k_base+1) 
  97.             * sizeof(PF))) == NULL) {
  98.             ewprintf("Out of memory");
  99.             return FALSE;
  100.         }
  101.         nold = ele->k_num - ele->k_base + 1;
  102.         for(i=0; i < nold; i++)
  103.             pfp[i] = ele->k_funcp[i];
  104.         while(--n1) pfp[i++] = curmap->map_default;
  105.         pfp[i] = funct;
  106.         ele->k_num = c;
  107.         ele->k_funcp = pfp;
  108.         } else if(n2 <= MAPELEDEF) {
  109.         if((pfp = (PF *)malloc((unsigned)(ele->k_num - c + 1) 
  110.             * sizeof(PF))) == NULL) {
  111.             ewprintf("Out of memory");
  112.             return FALSE;
  113.         }
  114.         nold = ele->k_num - ele->k_base + 1;
  115.         for(i=0; i < nold; i++)
  116.             pfp[i+n2] = ele->k_funcp[i];
  117.         while(--n2) pfp[n2] = curmap->map_default;
  118.         pfp[0] = funct;
  119.         ele->k_base = c;
  120.         ele->k_funcp = pfp;
  121.         } else {
  122.         if(curmap->map_num >= curmap->map_max &&
  123.             (curmap = realocmap(curmap)) == NULL) return FALSE;
  124.         if((pfp = (PF *)malloc(sizeof(PF))) == NULL) {
  125.             ewprintf("Out of memory");
  126.             return FALSE;
  127.         }
  128.         pfp[0] = funct;
  129.         for(mep = &curmap->map_element[curmap->map_num]; mep > ele; mep--) {
  130.             mep->k_base    = (mep-1)->k_base;
  131.             mep->k_num     = (mep-1)->k_num;
  132.             mep->k_funcp   = (mep-1)->k_funcp;
  133.             mep->k_prefmap = (mep-1)->k_prefmap;
  134.         }
  135.         ele->k_base = c;
  136.         ele->k_num = c;
  137.         ele->k_funcp = pfp;
  138.         ele->k_prefmap = NULL;
  139.         curmap->map_num++;
  140.         }
  141.         if(funct == prefix) {
  142.         if(pref_map != NULL) {
  143.             ele->k_prefmap = pref_map;
  144.         } else {
  145.             if((mp = (KEYMAP *)malloc(sizeof(KEYMAP) +
  146.                 (MAPINIT-1)*sizeof(MAP_ELEMENT))) == NULL) {
  147.             ewprintf("Out of memory");
  148.             ele->k_funcp[c - ele->k_base] = curmap->map_default;
  149.             return FALSE;
  150.             }
  151.             mp->map_num = 0;
  152.             mp->map_max = MAPINIT;
  153.             mp->map_default = rescan;
  154.             ele->k_prefmap = mp;
  155.         }
  156.         }
  157.     } else {
  158.         n1 = c - ele->k_base;
  159.         if(ele->k_funcp[n1] == funct && (funct!=prefix || pref_map==NULL ||
  160.             pref_map==ele->k_prefmap))
  161.         return TRUE;    /* no change */
  162.         if(funct!=prefix || ele->k_prefmap==NULL) {
  163.         if(ele->k_funcp[n1] == prefix)
  164.             ele->k_prefmap = (KEYMAP *)NULL;
  165.         ele->k_funcp[n1] = funct;    /* easy case */
  166.         if(funct==prefix) {
  167.             if(pref_map!=NULL)
  168.             ele->k_prefmap = pref_map;
  169.             else {
  170.             if((mp = (KEYMAP *)malloc(sizeof(KEYMAP) +
  171.                 (MAPINIT-1)*sizeof(MAP_ELEMENT))) == NULL) {
  172.                 ewprintf("Out of memory");
  173.                 ele->k_funcp[c - ele->k_base] = curmap->map_default;
  174.                 return FALSE;
  175.             }
  176.             mp->map_num = 0;
  177.             mp->map_max = MAPINIT;
  178.             mp->map_default = rescan;
  179.             ele->k_prefmap = mp;
  180.             }
  181.         }
  182.         } else {
  183.         /* this case is the splits */
  184.         /* determine which side of the break c goes on */
  185.         /* 0 = after break; 1 = before break */
  186.         n2 = 1;
  187.         for(i=0; n2 && i < n1; i++)
  188.             n2 &= ele->k_funcp[i] != prefix;
  189.         if(curmap->map_num >= curmap->map_max &&
  190.             (curmap = realocmap(curmap)) == NULL) return FALSE;
  191.         if((pfp = (PF *)malloc((unsigned)(ele->k_num - c + !n2) 
  192.             * sizeof(PF))) == NULL) {
  193.             ewprintf("Out of memory");
  194.             return FALSE;
  195.         }
  196.         ele->k_funcp[n1] = prefix;
  197.         for(i=n1+n2; i <= ele->k_num - ele->k_base; i++)
  198.             pfp[i-n1-n2] = ele->k_funcp[i];
  199.         for(mep = &curmap->map_element[curmap->map_num]; mep > ele; mep--) {
  200.             mep->k_base    = (mep-1)->k_base;
  201.             mep->k_num     = (mep-1)->k_num;
  202.             mep->k_funcp   = (mep-1)->k_funcp;
  203.             mep->k_prefmap = (mep-1)->k_prefmap;
  204.         }
  205.         ele->k_num = c - !n2;
  206.         (ele+1)->k_base = c + n2;
  207.         (ele+1)->k_funcp = pfp;
  208.         ele += !n2;
  209.         ele->k_prefmap = NULL;
  210.         curmap->map_num++;
  211.         if(pref_map == NULL) {
  212.             if((mp = (KEYMAP *)malloc(sizeof(KEYMAP) +
  213.                 (MAPINIT-1)*sizeof(MAP_ELEMENT))) == NULL) {
  214.             ewprintf("Out of memory");
  215.             ele->k_funcp[c - ele->k_base] = curmap->map_default;
  216.             return FALSE;
  217.             }
  218.             mp->map_num = 0;
  219.             mp->map_max = MAPINIT;
  220.             mp->map_default = rescan;
  221.             ele->k_prefmap = mp;
  222.         } else ele->k_prefmap = pref_map;
  223.         }
  224.     }
  225.     return TRUE;
  226. }
  227.  
  228. /* reallocate a keymap, used above */
  229. static KEYMAP *realocmap(curmap)
  230. register KEYMAP *curmap;
  231. {
  232.     register KEYMAP *mp;
  233.     register int i;
  234.     static VOID fixmap();
  235.     extern int nmaps;
  236.  
  237.     if((mp = (KEYMAP *)malloc((unsigned)(sizeof(KEYMAP)+
  238.         (curmap->map_max+(MAPGROW-1))*sizeof(MAP_ELEMENT)))) == NULL) {
  239.     ewprintf("Out of memory");
  240.     return NULL;
  241.     }
  242.     mp->map_num = curmap->map_num;
  243.     mp->map_max = curmap->map_max + MAPGROW;
  244.     mp->map_default = curmap->map_default;
  245.     for(i=curmap->map_num; i--; ) {
  246.     mp->map_element[i].k_base    = curmap->map_element[i].k_base;
  247.     mp->map_element[i].k_num    = curmap->map_element[i].k_num;
  248.     mp->map_element[i].k_funcp    = curmap->map_element[i].k_funcp;
  249.     mp->map_element[i].k_prefmap    = curmap->map_element[i].k_prefmap;
  250.     }
  251.     for(i=nmaps; i--; ) {
  252.     if(map_table[i].p_map == curmap) map_table[i].p_map = mp;
  253.     else fixmap(curmap, mp, map_table[i].p_map);
  254.     }
  255.     ele = &mp->map_element[ele - &curmap->map_element[0]];
  256.     return mp;
  257. }
  258.  
  259. /* fix references to a reallocated keymap (recursive) */
  260. static VOID fixmap(curmap, mp, mt)
  261. register KEYMAP *mt;
  262. register KEYMAP *curmap;
  263. KEYMAP *mp;
  264. {
  265.     register int i;
  266.  
  267.     for(i = mt->map_num; i--; ) {
  268.     if(mt->map_element[i].k_prefmap != NULL) {
  269.         if(mt->map_element[i].k_prefmap == curmap)
  270.             mt->map_element[i].k_prefmap = mp;
  271.         else fixmap(curmap, mp, mt->map_element[i].k_prefmap);
  272.     }
  273.     }
  274. }
  275.  
  276. /*
  277.  * do the input for local-set-key, global-set-key  and define-key
  278.  * then call remap to do the work.
  279.  */
  280.  
  281. static int dobind(curmap, p, unbind)
  282. register KEYMAP *curmap;
  283. char *p;
  284. int unbind;
  285. {
  286.     PF    funct;
  287.     char    prompt[80];
  288.     char    *pep;
  289.     int    c;
  290.     int    s;
  291.     KEYMAP    *pref_map = NULL;
  292.  
  293. #ifndef NO_MACRO
  294.     if(macrodef) {
  295.     /* keystrokes arn't collected.    Not hard, but pretty useless */
  296.     /* would not work for function keys in any case */
  297.         ewprintf("Can't rebind key in macro");
  298.         return FALSE;
  299.     }
  300. #ifndef NO_STARTUP
  301.     if(inmacro) {
  302.         for(s=0; s < maclcur->l_used - 1; s++) {
  303.         if(doscan(curmap, c=CHARMASK(maclcur->l_text[s])) != prefix) {
  304.             if(remap(curmap, c, prefix, (KEYMAP *)NULL) != TRUE) {
  305.             return FALSE;
  306.             }
  307.         }
  308.         curmap = ele->k_prefmap;
  309.         }
  310.         (VOID) doscan(curmap, c=maclcur->l_text[s]);
  311.         maclcur = maclcur->l_fp;
  312.     } else {
  313. #endif
  314. #endif
  315.         (VOID) strcpy(prompt, p);
  316.         pep = prompt + strlen(prompt);
  317.         for(;;) {
  318.         ewprintf("%s", prompt);
  319.         pep[-1] = ' ';
  320.         pep = keyname(pep, c = getkey(FALSE));
  321.         if(doscan(curmap,c) != prefix) break;
  322.         *pep++ = '-';
  323.         *pep = '\0';
  324.         curmap = ele->k_prefmap;
  325.         }
  326. #ifndef NO_STARTUP
  327.     }
  328. #endif
  329.     if(unbind) funct = rescan;
  330.     else {
  331.         if ((s=eread("%s to command: ", prompt, 80, EFFUNC|EFNEW, prompt))
  332.             != TRUE) return s;
  333.         if (((funct = name_function(prompt)) == prefix) ?
  334.                 (pref_map = name_map(prompt)) == NULL : funct==NULL) {
  335.         ewprintf("[No match]");
  336.         return FALSE;
  337.         }
  338.     }
  339.     return remap(curmap, c, funct, pref_map);
  340. }
  341.  
  342. /*
  343.  * bindkey: bind key sequence to a function in
  344.  * the specified map.  Used by excline so it can bind function keys.
  345.  * To close to release to change calling sequence, should just pass
  346.  * KEYMAP *curmap rather than KEYMAP **mapp.
  347. */
  348. #ifdef    BINDKEY
  349. bindkey(mapp, fname, keys, kcount)
  350. KEYMAP **mapp;
  351. char *fname;
  352. KCHAR *keys;
  353. int kcount;
  354. {
  355.     KEYMAP    *curmap = *mapp;
  356.     PF    funct;
  357.     int    c;
  358.     KEYMAP    *pref_map = NULL;
  359.  
  360.     if(fname == NULL) funct = rescan;
  361.     else if (((funct = name_function(fname)) == prefix) ?
  362.         (pref_map = name_map(fname)) == NULL : funct==NULL) {
  363.         ewprintf("[No match: %s]", fname);
  364.         return FALSE;
  365.     }
  366.     while(--kcount) {
  367.         if(doscan(curmap, c = *keys++) != prefix) {
  368.         if(remap(curmap, c, prefix, (KEYMAP *)NULL) != TRUE)
  369.             return FALSE;
  370.         }
  371.         curmap = ele->k_prefmap;
  372.     }
  373.     (VOID) doscan(curmap, c = *keys);
  374.     return remap(curmap, c, funct, pref_map);
  375. }
  376. #endif
  377.  
  378. /*
  379.  * This function modifies the fundamental keyboard map.
  380.  */
  381. /*ARGSUSED*/
  382. bindtokey(f, n)
  383. {
  384.     return dobind(map_table[0].p_map, "Global set key: ", FALSE);
  385. }
  386.  
  387. /*
  388.  * This function modifies the current mode's keyboard map.
  389.  */
  390. /*ARGSUSED*/
  391. localbind(f, n)
  392. {
  393.     return dobind(curbp->b_modes[curbp->b_nmodes]->p_map, "Local set key: ",
  394.     FALSE);
  395. }
  396.  
  397. /*
  398.  * This function redefines a key in any keymap.
  399.  */
  400. /*ARGSUSED*/
  401. define_key(f, n)
  402. {
  403.     static char buf[48] = "Define key map: ";
  404.     MAPS *mp;
  405.     char *strncat();
  406.  
  407.     buf[16] = '\0';
  408.     if(eread(buf, &buf[16], 48 - 16, EFNEW) != TRUE) return FALSE;
  409.     if((mp = name_mode(&buf[16])) == NULL) {
  410.     ewprintf("Unknown map %s", &buf[16]);
  411.     return FALSE;
  412.     }
  413.     (VOID) strncat(&buf[16], " key: ", 48-16-1);
  414.     return dobind(mp->p_map, buf, FALSE);
  415. }
  416.  
  417. unbindtokey(f, n)
  418. int f, n;
  419. {
  420.     return dobind(map_table[0].p_map, "Global unset key: ", TRUE);
  421. }
  422.  
  423. localunbind(f, n)
  424. int f, n;
  425. {
  426.     return dobind(curbp->b_modes[curbp->b_nmodes]->p_map, "Local unset key: ",
  427.     TRUE);
  428. }
  429.  
  430. /*
  431.  * Extended command. Call the message line
  432.  * routine to read in the command name and apply autocompletion
  433.  * to it. When it comes back, look the name up in the symbol table
  434.  * and run the command if it is found.
  435.  * Print an error if there is anything wrong.
  436.  */
  437. extend(f, n)
  438. {
  439.     PF    funct;
  440.     int    s;
  441.     char    xname[NXNAME];
  442.  
  443.     if(!(f & FFARG)) s = eread("M-x ", xname, NXNAME, EFNEW|EFFUNC);
  444.     else         s = eread("%d M-x ", xname, NXNAME, EFNEW|EFFUNC, n);
  445.     if(s != TRUE) return s;
  446.     if((funct = name_function(xname)) != NULL) {
  447. #ifndef NO_MACRO
  448.         if(macrodef) {
  449.         LINE *lp = maclcur;
  450.         macro[macrocount-1].m_funct = funct;
  451.         maclcur = lp->l_bp;
  452.         maclcur->l_fp = lp->l_fp;
  453.         free((char *)lp);
  454.         }
  455. #endif
  456.         return (*funct)(f, n);
  457.     }
  458.     ewprintf("[No match]");
  459.     return FALSE;
  460. }
  461.  
  462. #ifndef NO_STARTUP
  463. /*
  464.  * Define the commands needed to do startup-file processing.
  465.  * This code is mostly a kludge just so we can get startup-file processing.
  466.  *
  467.  * If you're serious about having this code, you should rewrite it.
  468.  * To wit:
  469.  *    It has lots of funny things in it to make the startup-file look
  470.  *    like a GNU startup file; mostly dealing with parens and semicolons.
  471.  *    This should all vanish.
  472.  *
  473.  * We define eval-expression because it's easy.     It can make
  474.  * *-set-key or define-key set an arbitrary key sequence, so it isn't
  475.  * useless.
  476.  */
  477.  
  478. /*
  479.  * evalexpr - get one line from the user, and run it.
  480.  */
  481. /*ARGSUSED*/
  482. evalexpr(f, n)
  483. {
  484.     int    s;
  485.     char    exbuf[128];
  486.  
  487.     if ((s = ereply("Eval: ", exbuf, 128)) != TRUE)
  488.         return s;
  489.     return excline(exbuf);
  490. }
  491. /*
  492.  * evalbuffer - evaluate the current buffer as line commands. Useful
  493.  *    for testing startup files.
  494.  */
  495. /*ARGSUSED*/
  496. evalbuffer(f, n)
  497. {
  498.     register LINE    *lp;
  499.     register BUFFER *bp = curbp;
  500.     register int    s;
  501.     static char    excbuf[128];
  502.  
  503.     for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp)) {
  504.         if (llength(lp) >= 128) return FALSE;
  505.         (VOID) strncpy(excbuf, ltext(lp), llength(lp));
  506.         excbuf[llength(lp)] = '\0';    /* make sure it's terminated */
  507.         if ((s = excline(excbuf)) != TRUE) return s;
  508.     }
  509.     return TRUE;
  510. }
  511. /*
  512.  * evalfile - go get a file and evaluate it as line commands. You can
  513.  *    go get your own startup file if need be.
  514.  */
  515. /*ARGSUSED*/
  516. evalfile(f, n)
  517. {
  518.     register int    s;
  519.     char        fname[NFILEN];
  520.  
  521.     if ((s = ereply("Load file: ", fname, NFILEN)) != TRUE)
  522.         return s;
  523.     return load(fname);
  524. }
  525.  
  526. /*
  527.  * load - go load the file name we got passed.
  528.  */
  529. load(fname) char *fname; {
  530.     int    s = TRUE;
  531.     int    nbytes;
  532.     char    excbuf[128];
  533.  
  534.     if ((fname = adjustname(fname)) == NULL)
  535.         return FALSE;    /* just to be careful */
  536.  
  537.     if (ffropen(fname) != FIOSUC) return FALSE;
  538.     while ((s = ffgetline(excbuf, sizeof(excbuf)-1, &nbytes)) == FIOSUC) {
  539.         excbuf[nbytes] = '\0';
  540.         if (excline(excbuf) != TRUE) {
  541.             s = FIOERR;
  542.             ewprintf("Error loading file %s", fname);
  543.             break;
  544.         }
  545.     }
  546.     (VOID) ffclose();
  547.     excbuf[nbytes] = '\0';
  548.     if(s!=FIOEOF || (nbytes && excline(excbuf)!=TRUE))
  549.         return FALSE;
  550.     return TRUE;
  551. }
  552.  
  553. /*
  554.  * excline - run a line from a load file or eval-expression.
  555.  * if FKEYS is defined, duplicate functionallity of dobind so function
  556.  * key values don't have to fit in type char.
  557.  */
  558. excline(line)
  559. register char *line;
  560. {
  561.     register char    *funcp, *argp = NULL;
  562.     register int    c;
  563.     int        status;
  564.     int    f, n;
  565.     LINE    *lp, *np;
  566.     PF    fp;
  567. #ifdef    FKEYS
  568.     int    bind;
  569.     KEYMAP    *curmap;
  570.     MAPS    *mp;
  571. #define BINDARG        0    /* this arg is key to bind (local/global set key) */
  572. #define    BINDNO        1    /* not binding or non-quoted BINDARG */
  573. #define BINDNEXT    2    /* next arg " (define-key) */
  574. #define BINDDO        3    /* already found key to bind */
  575. #define BINDEXT 1        /* space for trailing \0 */
  576. #else
  577. #define BINDEXT 0
  578. #endif
  579.     PF    name_function();
  580.     LINE    *lalloc();
  581.     static    char    *skipwhite(), *parsetoken();
  582.  
  583.     if(macrodef || inmacro) {
  584.         ewprintf("Not now!");
  585.         return FALSE;
  586.     }
  587.  
  588.     f = 0;
  589.     n = 1;
  590.     funcp = skipwhite(line);
  591.     if (*funcp == '\0') return TRUE;    /* No error on blank lines */
  592.     line = parsetoken(funcp);
  593.     if (*line != '\0') {
  594.         *line++ = '\0';
  595.         line = skipwhite(line);
  596.         if ((*line >= '0' && *line <= '9') || *line == '-') {
  597.             argp = line;
  598.             line = parsetoken(line);
  599.         }
  600.     }
  601.  
  602.     if (argp != NULL) {
  603.         f = FFARG;
  604.         n = atoi(argp);
  605.     }
  606.     if((fp = name_function(funcp)) == NULL) {
  607.         ewprintf("Unknown function: %s", funcp);
  608.         return FALSE;
  609.     }
  610. #ifdef    FKEYS
  611.     if(fp == bindtokey || fp == unbindtokey) {
  612.         bind = BINDARG;
  613.         curmap = map_table[0].p_map;
  614.     } else if(fp == localbind || fp == localunbind) {
  615.         bind = BINDARG;
  616.         curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
  617.     } else if(fp == define_key) bind = BINDNEXT;
  618.     else bind = BINDNO;
  619. #endif
  620.     /* Pack away all the args now...    */
  621.     if((np = lalloc(0))==FALSE) return FALSE;
  622.     np->l_fp = np->l_bp = maclcur = np;
  623.     while (*line != '\0') {
  624.         argp = skipwhite(line);
  625.         if (*argp == '\0') break;
  626.         line = parsetoken(argp);
  627.         if (*argp != '"') {
  628.             if (*argp == '\'') ++argp;
  629.             if((lp = lalloc((int)(line-argp)+BINDEXT))==NULL) {
  630.             status = FALSE;
  631.             goto cleanup;
  632.             }
  633.             bcopy(argp, ltext(lp), (int)(line-argp));
  634. #ifdef    FKEYS
  635.             lp->l_used--;    /* don't count BINDEXT! */
  636.             if(bind == BINDARG) bind = BINDNO;
  637. #endif
  638.         } else {    /* Quoted strings special */
  639.             ++argp;
  640. #ifdef    FKEYS
  641.             if(bind != BINDARG) {
  642. #endif
  643.             if((lp = lalloc((int)(line-argp)+BINDEXT))==NULL) {
  644.                 status = FALSE;
  645.                 goto cleanup;
  646.             }
  647.             lp->l_used = 0;
  648. #ifdef    FKEYS
  649.             } else {
  650.             key.k_count = 0;
  651.             }
  652. #endif
  653.             while (*argp != '"' && *argp != '\0') {
  654.             if (*argp != '\\') c = *argp++;
  655.             else {
  656.                 switch(*++argp) {
  657.                 case 't': case 'T':
  658.                     c = CCHR('I');
  659.                     break;
  660.                 case 'n': case 'N':
  661.                     c = CCHR('J');
  662.                     break;
  663.                 case 'r': case 'R':
  664.                     c = CCHR('M');
  665.                     break;
  666.                 case 'e': case 'E':
  667.                     c = CCHR('[');
  668.                     break;
  669.                 case '^':
  670. /* split into two statements due to bug in OSK cpp */
  671.                     c = CHARMASK(*++argp);
  672.                     c = ISLOWER(c) ?
  673.                     CCHR(TOUPPER(c)) : CCHR(c);
  674.                     break;
  675.                 case '0': case '1': case '2': case '3':
  676.                 case '4': case '5': case '6': case '7':
  677.                     c = *argp - '0';
  678.                     if(argp[1] <= '7' && argp[1] >= '0') {
  679.                         c <<= 3;
  680.                     c += *++argp - '0';
  681.                     if(argp[1] <= '7' && argp[1] >= '0') {
  682.                         c <<= 3;
  683.                         c += *++argp - '0';
  684.                     }
  685.                     }
  686.                     break;
  687. #ifdef    FKEYS
  688.                 case 'f': case 'F':
  689.                     c = *++argp - '0';
  690.                     if(ISDIGIT(argp[1])) {
  691.                     c *= 10;
  692.                     c += *++argp - '0';
  693.                     }
  694.                     c += KFIRST;
  695.                     break;
  696. #endif
  697.                 default:
  698.                     c = CHARMASK(*argp);
  699.                     break;
  700.                 }
  701.                 argp++;
  702.             }
  703. #ifdef    FKEYS
  704.             if(bind == BINDARG)
  705.                 key.k_chars[key.k_count++] = c;
  706.             else
  707. #endif
  708.                 lp->l_text[lp->l_used++] = c;
  709.             }
  710.             if(*line) line++;
  711.         }
  712. #ifdef    FKEYS
  713.         switch(bind) {
  714.             case BINDARG:
  715.             bind = BINDDO;
  716.             break;
  717.             case BINDNEXT:
  718.             lp->l_text[lp->l_used] = '\0';
  719.             if((mp = name_mode(lp->l_text)) == NULL) {
  720.                 ewprintf("No such mode: %s", lp->l_text);
  721.                 status = FALSE;
  722.                 free((char *)lp);
  723.                 goto cleanup;
  724.             }
  725.             curmap = mp->p_map;
  726.             free((char *)lp);
  727.             bind = BINDARG;
  728.             break;
  729.             default:
  730. #endif
  731.             lp->l_fp = np->l_fp;
  732.             lp->l_bp = np;
  733.             np->l_fp = lp;
  734.             np = lp;
  735. #ifdef    FKEYS
  736.         }
  737. #endif
  738.     }
  739. #ifdef    FKEYS
  740.     switch(bind) {
  741.         default:
  742.         ewprintf("Bad args to set key");
  743.         status = FALSE;
  744.         break;
  745.         case BINDDO:
  746.             if(fp != unbindtokey && fp != localunbind) {
  747.             lp->l_text[lp->l_used] = '\0';
  748.             status = bindkey(&curmap, lp->l_text, key.k_chars, key.k_count);
  749.         } else status = bindkey(&curmap, (char *)NULL, key.k_chars, key.k_count);
  750.         break;
  751.         case BINDNO:
  752. #endif
  753.         inmacro = TRUE;
  754.         maclcur = maclcur->l_fp;
  755.         status = (*fp)(f, n);
  756.         inmacro = FALSE;
  757. #ifdef    FKEYS
  758.     }
  759. #endif
  760. cleanup:
  761.     lp = maclcur->l_fp;
  762.     while(lp!=maclcur) {
  763.         np = lp->l_fp;
  764.         free((char *)lp);
  765.         lp = np;
  766.     }
  767.     free((char *)lp);
  768.     return status;
  769. }
  770.  
  771. /*
  772.  * a pair of utility functions for the above
  773.  */
  774. static char *
  775. skipwhite(s)
  776. register char *s;
  777. {
  778.     while(*s == ' ' || *s == '\t' || *s == ')' || *s == '(') s++;
  779.     if (*s == ';') *s = '\0' ;
  780.     return s;
  781. }
  782.  
  783. static char *
  784. parsetoken(s)
  785. register char *s;
  786. {
  787.     if (*s != '"') {
  788.         while(*s && *s!=' ' && *s!='\t' && *s!=')' && *s!='(') s++;
  789.         if(*s==';') *s='\0';
  790.     } else
  791.         do {    /* Strings get special treatment */
  792.             /* Beware: You can \ out the end of the string! */
  793.         if (*s == '\\') ++s;
  794.         } while (*++s != '"' && *s != '\0');
  795.     return s;
  796. }
  797. #endif
  798.